package tk.pak0.audiomidifier.model.audio.pitchdet;

import javax.sound.sampled.LineUnavailableException;

import org.apache.log4j.Logger;

import tk.pak0.audiomidifier.model.audio.AudioTools;

public class ZeroCrossing extends A_PitchDetector{
	private double previousValue = -1;
	private static Logger log = Logger.getLogger(ZeroCrossing.class);
	
	public ZeroCrossing(float sampleRate, int smoothFactor){
		super(sampleRate, smoothFactor);
	}
	@Override
	public double getPitch(short[] buffer) throws LineUnavailableException {
		/* Cogemos una instancia de audioTools
		 * y convertimos el array a double  
		 */
		AudioTools audioTools = AudioTools.getInstance();
		int bufferSize = buffer.length;
		double[] hannWindow = audioTools.crearHannWindow(bufferSize);
		short[] winBuffer = new short[bufferSize];
		
		for(int i=0; i < bufferSize ; i++){
			winBuffer[i] = (short) (buffer[i] * hannWindow[i]);
		}
		log.debug("Multiplicado chunk por hannWindow");
		
		int accu=0, accuTemp=0, divisor=0;
		double media=0, valorPrev=0, valorAct=0;
		
		for(int i=0; i < bufferSize; i++){
			valorAct = winBuffer[i];
			if(i != 0 && (valorAct==0 || (Math.abs(valorAct + valorPrev) < (Math.abs(valorAct) + Math.abs(valorPrev))))){
//				log.trace("Cruce de cero! "+valorAct+" ~ "+valorPrev+" accu "+accu+" accuTemp "+accuTemp);
				accu = accuTemp + accu;
				divisor++;
				accuTemp = 0;
			}else{
				accuTemp++;
			}
			valorPrev = valorAct;
		}
		
		if(divisor == 0){
			divisor = 1;
		}
		
		log.trace("Acumulador "+accu);
		log.trace("Divisor "+divisor);
		media = accu /divisor;
		log.trace("Raw media "+media);
		// convertir de media a frecuencia
		media = averageToFreq(media);
		log.trace("Media after method "+media);
		
		int smoothFactor = this.getSmoothFactor();
		if(smoothFactor > 0){
			if(previousValue == -1){
				previousValue = media;
			}else{
				media = (1-(smoothFactor/100))*previousValue + (smoothFactor/100)*media;
				previousValue = media;
			}
		}
		
		return media;
	}
	
	private double averageToFreq(double average){
		return average/(1/super.getSampleRate());
	}
}
